<?php
	namespace Admin\Controller;
	use Think\Controller;
	use Think\Page;
	use Admin\Model\AuthRuleModel;
	class AdminController extends Controller{

		/**
		 * 后台控制器初始化
		 */
		 public function _initialize(){
			 //检测是否登录
			 define('UID',is_login());
				if( !UID ){
					$this->redirect('Public/login');
				}
			 /* 读取数据库中的配置 */
			 $config =   S('DB_CONFIG_DATA');
			 if(!$config){
				 $config =   api('Config/lists');
				  S('DB_CONFIG_DATA',$config);
			 }
			 C($config); //添加配置

			 //检测是否为超级管理员
			 define ('IS_ROOT',is_administrator());
			 
			// 检测访问权限
			$access=$this->accessControl();
			if($access===false){
				$this->error('403:禁止访问');
			}else if($access===null){
				
					//检测节点权限
					$dynamic=$this->checkDynamic();
					if($dynamic===null){
						//检测非动态权限
						$rule=strtolower(MODULE_NAME.'/'.CONTROLLER_NAME.'/'.ACTION_NAME);
						
						if(!$this->checkRule($rule)){
							
							$this->error('未授权访问!');
						}
					}
					else if($dynamic === false){
						$this->error('未授权访问!');
					}
			}
			 $this->assign('__MENU__', $this->getMenus());
		 }
		 /**
		 * 权限检测
		 * @param string  $rule    检测的规则
		 * @param string  $mode    check模式
		 * @return boolean
		 */
		final protected function checkRule($rule, $type=AuthRuleModel::RULE_URL, $mode='url'){
			if(IS_ROOT){
				return true;//管理员允许访问任何页面
			}
			static $Auth    =   null;
			if (!$Auth) {
				$Auth       =   new \Think\Auth();
			}
			if(!$Auth->check($rule,UID,$type,$mode)){
				return false;
			}
			return true;
		}
		 /**
		 * action访问控制,在 **登陆成功** 后执行的第一项权限检测任务
		 *
		 * @return boolean|null  返回值必须使用 `===` 进行判断
		 *
		 *   返回 **false**, 不允许任何人访问(超管除外)
		 *   返回 **true**, 允许任何管理员访问,无需执行节点权限检测
		 *   返回 **null**, 需要继续执行节点权限检测决定是否允许访问
		 */

		 final protected function accessControl(){
			 if(IS_ROOT){
				 return true;//管理员允许访问任何页面
			 }
			 $allow=C('ALLOW_VISIT');
			 $deny=C('DENY_VISIT');
			 $check=strtolower(CONTROLLER_NAME.'/'.ACTION_NAME);
			 if(!empty($deny) && in_array($check, $deny)) {
					return false;
			 }
			 if(!empty($allow) && in_array($check, $allow)){
				 return true;
			 }
			 return null;//需要检测节点权限
		 }
		 /**
		 * 检测是否是需要动态判断的权限
		 * @return boolean|null
		 *      返回true则表示当前访问有权限
		 *      返回false则表示当前访问无权限
		 *      返回null，则会进入checkRule根据节点授权判断权限
		 *
		 */
		 protected function checkDynamic(){
			 if(IS_ROOT){
				 return true;//管理员允许访问任何页面
			 }
			 return null;
		 }

		 /**
		 * 获取控制器菜单数组,二级菜单元素位于一级菜单的'_child'元素中
		 
		 */
		 final protected function getMenus(){
			 if(empty($menus)){
				 $where['pid']=0;
				 $where['hide']=0;
				 $menus['main']  =   M('Menu')->where($where)->order('sort asc')->select();

				 $menus['child'] = array(); //设置子节点

				 //高亮主菜单
				$current = M('Menu')->where("url like '%".CONTROLLER_NAME."/".ACTION_NAME."%'")->field('id')->find();
				
				 // 获取当前主菜单的子菜单项
				if($current){
					$nav=D('Menu')->getPath($current['id']);
				
					$nav_first_title = $nav[0]['title'];
		
					
					 foreach($menus['main'] as $key=>$item){
						 if(!is_array($item)||empty($item['url'])||empty($item['title'])){
							 $this->error('控制器基类$menus属性元素配置有误');
						 }
						 if(stripos($item['url'],MODULE_NAME)!==0 ){
							 $item['url'] = MODULE_NAME.'/'.$item['url'];
						 }
						 // 判断主菜单权限
						 
						if (!IS_ROOT && !$this->checkRule($item['url'],AuthRuleModel::RULE_MAIN,null)) {
							unset($menus['main'][$key]);
							continue;//继续循环
						}
						
						 if($item['title']==$nav_first_title){
							 $menus['main'][$key]['class']='current';
							 //生成child树
							 $groups=D('Menu')->where("pid = {$item['id']}")->distinct(true)->field('group')->select();
							
							 if($groups){
								 $groups=array_column($groups,'group');
							 }else{
								 $groups=array();
							 }
							  //获取二级分类的合法url
							  $where=array();
							  $where['pid']=$item['id'];
							  $where['hide']=0;
							  $second_urls=M('Menu')->where($where)->field('id,url')->select();
							  // 按照分组生成子菜单树
							  foreach($groups as $g){
								  $map['group']=$g;
								  $map['pid']=$item['id'];
								  $map['hide']=0;
								  $menuList=M('Menu')->where($map)->field('id,title,url,pid,tip')->select();
								  $menus['child'][$g]=list_to_tree($menuList,'id','pid','operater',$item['id']);
							  }

								 if($menus['child'] === array()){
										//$this->error('主菜单下缺少子菜单，请去系统=》后台菜单管理里添加');
								 }
						 }
						
					 }
				 }
			 }
			 //echo "<pre/>";print_r($menus);
			 return $menus;
		 }
		
		/*
		 * @param boolean      $field   单表模型用不到该参数,要用在多表join时为field()方法指定参数
		*/
		protected function lists($model,$where=array(),$order='',$base = array('status'=>array('egt',0)),$field=true){
			$option=array();
			if(is_string($model)){
				 $model  =   M($model);
			}
			$options['where']=array_filter(array_merge((array)$base,(array)$where),function($val){
				if($val===''||$val===null){
					return false;
				}else{
					return true;
				}
			});
			if( empty($options['where'])){
				unset($options['where']);
			}

			$total        =   $model->where($options['where'])->count();
			$listRows= C('LIST_ROWS')>0 ? C('LIST_ROWS'):10;
			$page= new Page($total ,$listRows);
			$p= $page->show();
			$options['limit']= $page->firstRow .','.$page->listRows;
			//echo "<pre/>";print_r($options);
			$this->assign('_page', $p? $p: '');

			$model->setProperty('options',$options);
			return $model->field($field)->select();
		}
		/**
		 * 禁用条目
		 * @param string $model 模型名称,供D函数使用的参数
		 * @param array  $where 查询时的 where()方法的参数
		 * @param array  $msg   执行正确和错误的消息,可以设置四个元素 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
		 *                     url为跳转页面,ajax是否ajax方式(数字则为倒数计时秒数)
		 */
		protected function forbid($model, $where=array(), $msg=array('success'=>'状态禁用成功！','error'=>'状态禁用失败！')){
			$data=array('status'=>0);
			$this->editRow($model, $data, $where, $msg);

		}
		 /**
		 * 恢复条目
		 * @param string $model 模型名称,供D函数使用的参数
		 * @param array  $where 查询时的where()方法的参数
		 * @param array  $msg   执行正确和错误的消息 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
		 *                     url为跳转页面,ajax是否ajax方式(数字则为倒数计时秒数)
		 */
		 protected function resume($model ,$where=array(), $msg=array('success'=>'状态恢复成功！','error'=>'状态恢复失败！')){
			 $data=array('status'=>1);
			  $this->editRow($model, $data, $where, $msg);
		 }
		/* 对数据表中的单行或多行记录执行修改 GET参数id为数字或逗号分隔的数字
			*
		 * @param string $model 模型名称,供M函数使用的参数
		 * @param array  $data  修改的数据
		 * @param array  $where 查询时的where()方法的参数
		 * @param array  $msg   执行正确和错误的消息 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
		 *                     url为跳转页面,ajax是否ajax方式(数字则为倒数计时秒数)
		 **/
		 /**
		 * 条目假删除
		 * @param string $model 模型名称,供D函数使用的参数
		 * @param array  $where 查询时的where()方法的参数
		 * @param array  $msg   执行正确和错误的消息 array('success'=>'','error'=>'', 'url'=>'','ajax'=>false)
		 *                     url为跳转页面,ajax是否ajax方式(数字则为倒数计时秒数)
		 */
		   protected function delete ( $model , $where = array() , $msg = array( 'success'=>'删除成功！', 'error'=>'删除失败！')) {
				$data['status']         =   -1;
				$data['update_time']    =   NOW_TIME;
				$this->editRow(   $model , $data, $where, $msg);
			}
		 final protected function editRow($model ,$data, $where,$msg){
			 $id=array_unique((array)I('id',0));
			 $id=is_array($id)?implode(",",$id):$id;
			 $where = array_merge( array('id' => array('in', $id )) ,(array)$where );
			 $msg   = array_merge( array( 'success'=>'操作成功！', 'error'=>'操作失败！', 'url'=>'' ,'ajax'=>IS_AJAX) , (array)$msg );
			 if( M($model)->where($where)->save($data)!==false ) {
				$this->success($msg['success'],$msg['url'],$msg['ajax']);
			}else{
				$this->error($msg['error'],$msg['url'],$msg['ajax']);
			}

		 }
		 /**
		 * 返回后台节点数据
		 * @param boolean $tree    是否返回多维数组结构(生成菜单时用到),为false返回一维数组(生成权限节点时用到)
		 * @retrun array
		 *
		 * 注意,返回的主菜单节点数组中有'controller'元素,以供区分子节点和主节点
		 *
		
		 */
		 final protected function returnNodes($tree=true){
			static $tree_nodes=array();
			if($tree && !empty($tree_nodes[(int)$tree])){
				return $tree_nodes[$tree];
			}
			if((int)$tree){
				$list=M('Menu')->field('id,pid,title,url,tip,hide')->order('sort asc')->select();
				foreach($list as $key=>$value){
					if( strpos($value['url'],MODULE_NAME)!==0 ){
						$list[$key]['url']=MODULE_NAME.'/'.$value['url'];
					}
				}
				$nodes=list_to_tree($list,$pk='id',$pid='pid',$child='operator',$root=0);
				foreach($nodes as $key=>$value){
					if(!empty($value['operator'])){
						$nodes[$key]['child']=$value['operator'];
						unset($nodes[$key]['operator']);
					}
				}
			}
			else{
				$nodes = M('Menu')->field('title,url,tip,pid')->order('sort asc')->select();
				foreach ($nodes as $key => $value) {
					if( stripos($value['url'],MODULE_NAME)!==0 ){
						$nodes[$key]['url'] = MODULE_NAME.'/'.$value['url'];
					}
				}
			}
			 $tree_nodes[(int)$tree]   = $nodes;
			 return $nodes;
		 }
		 /**
		 * 设置一条或者多条数据的状态
		 */
		 public function setstatus($Model=CONTROLLER_NAME){
		
			$status=I('status');
			$id=I('ids',0);
			if(empty($id)){
				$this->error('请选择要操作的数据!');
			}
			$map['id']=array('in',$id);
			
			switch($status){
				case -1:
					$this->delete($Model, $map );
					break;
				case 0:
					$this->forbid($Model,$map);
					break;
				case 1:
					$this->resume($Model,$map);
					break;
				default: 
					$this->error('参数非法');
			}
		 }
	}
?>